package com.qilu.careprogram.service.impl;

import com.qilu.careprogram.dao.PatientInfoDAO;
import com.qilu.careprogram.model.Result;
import com.qilu.careprogram.pojo.dto.PatientLoginDTO;
import com.qilu.careprogram.dao.ProstateCancerDAO;
import com.qilu.careprogram.dao.ReturnVisitListDAO;
import com.qilu.careprogram.model.enums.DesEnum;
import com.qilu.careprogram.pojo.dto.AddDrugDTO;
import com.qilu.careprogram.pojo.dto.UpdateDrugDTO;
import com.qilu.careprogram.pojo.entity.Drug;
import com.qilu.careprogram.pojo.dto.*;
import com.qilu.careprogram.pojo.entity.Carousel;
import com.qilu.careprogram.pojo.entity.HotArticle;
import com.qilu.careprogram.pojo.dto.NurseInfoDTO;
import com.qilu.careprogram.pojo.dto.UnregisteredPatientDTO;
import com.qilu.careprogram.pojo.dto.ProstateSurgeryInfoDTO;
import com.qilu.careprogram.pojo.entity.PatientInfo;
import com.qilu.careprogram.pojo.entity.PatientInit;
import com.qilu.careprogram.pojo.entity.ProstateCancer;
import com.qilu.careprogram.pojo.entity.ReturnVisitList;
import com.qilu.careprogram.pojo.vo.*;
import com.qilu.careprogram.pojo.entity.UserLike;
import com.qilu.careprogram.service.PatientExceptionService;
import com.qilu.careprogram.exception.BusinessException;
import com.qilu.careprogram.service.PatientService;
import com.qilu.careprogram.utils.CheckIdNumberUtil;
import com.qilu.careprogram.utils.DesUtil;
import com.qilu.careprogram.utils.JwtUtil;
import com.qilu.careprogram.utils.Md5Util;
import com.qilu.careprogram.sms.SmsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.time.Duration;
import java.time.LocalDateTime;

@Slf4j
@Service
public class PatientServiceImpl implements PatientService {

    @Resource
    PatientInfoDAO patientInfoDAO;
    @Resource
    ReturnVisitListDAO returnVisitListDAO;
    @Resource
    ProstateCancerDAO prostateCancerDAO;
    @Resource
    private TransactionTemplate transactionTemplate;
    DesUtil desUtil = new DesUtil(DesEnum.DesKey.KEY.toString());
    @Resource
    PatientExceptionService patientExceptionService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private SmsService smsService;

    @Override
    public List<Long> getUserLikeHotArticlesId(String hospitalNumber) {
        try {
            return patientInfoDAO.selectHotArticleIdsByHospitalNumber(hospitalNumber);
        } catch (Exception e) {
            log.error("查询用户收藏文章ID失败", e);
            throw new BusinessException("查询用户收藏文章ID失败");
        }
    }

    @Override
    public void deleteLike(String hospitalNumber, Long hotArticleId) {
        try {
            int rows = patientInfoDAO.deleteByHospitalNumberAndArticleId(hospitalNumber, hotArticleId);
            if (rows == 0) {
                throw new BusinessException("未找到该收藏记录");
            }
        } catch (Exception e) {
            log.error("取消收藏失败", e);
            throw new BusinessException("取消收藏失败");
        }
    }

    @Override
    public void addLike(String hospitalNumber, Long hotArticleId) {

        try {
            // 先检查文章是否存在
            System.out.println("接收的文章ID: " + hotArticleId);
            HotArticle article = patientInfoDAO.selectHotArticleById(hotArticleId);
            if (article == null) {
                throw new BusinessException("文章不存在");
            }
            // 插入收藏记录
            UserLike userLike = new UserLike();
            userLike.setHospitalNumber(hospitalNumber);
            userLike.setHotArticleId(hotArticleId);
            patientInfoDAO.insertUserLike(userLike);
        } catch (DuplicateKeyException e) {
            log.warn("文章已收藏: hospitalNumber={}, articleId={}", hospitalNumber, hotArticleId);
            throw e; // 抛出重复键异常，由controller处理
        } catch (Exception e) {
            log.error("添加收藏失败", e);
            throw new BusinessException("添加收藏失败");
        }
    }

    @Override
    public List<HotArticle> getUserLike(String hospitalNumber) {
        try {
            return patientInfoDAO.selectHotArticlesByUserLikes(hospitalNumber);
        } catch (Exception e) {
            log.error("查询用户收藏文章详情失败", e);
            throw new BusinessException("查询用户收藏文章详情失败");
        }
    }

    @Override
    public List<Carousel> getAllCarousel() {
        try {
            return patientInfoDAO.getAllCarousel();
        } catch (Exception e) {
            log.error("获取轮播图列表失败", e);
            throw new BusinessException("获取轮播图列表失败");
        }
    }

    @Override
    public List<HotArticle> getAllHotArticles() {
        try {
            return patientInfoDAO.getAllHotArticles();
        } catch (Exception e) {
            log.error("获取热门文章列表失败", e);
            throw new BusinessException("获取热门文章列表失败");
        }
    }

    @Override
    public void addCarousel(AddCarouselDTO addCarouselDTO) {
        try {
            // 转换DTO为实体
            Carousel carousel = new Carousel();
            carousel.setPicture(addCarouselDTO.getUrl());
            carousel.setAuthority(addCarouselDTO.getAuthority());
            carousel.setIsused(addCarouselDTO.getIsused());

            patientInfoDAO.addCarousel(carousel);
        } catch (Exception e) {
            log.error("添加轮播图失败", e);
            throw new BusinessException("添加轮播图失败");
        }
    }

    @Override
    public void addHotArticle(AddHotArticleDTO addHotArticleDTO) {
        try {
            HotArticle article = new HotArticle();
            article.setName(addHotArticleDTO.getName());
            article.setDescription(addHotArticleDTO.getDescription());
            article.setPicture(addHotArticleDTO.getPicture());
            article.setPcurl(addHotArticleDTO.getPcurl());
            article.setAuthority(addHotArticleDTO.getAuthority());
            article.setIsused(addHotArticleDTO.getIsused());

            patientInfoDAO.addHotArticle(article);
        } catch (Exception e) {
            log.error("添加热门文章失败", e);
            throw new BusinessException("添加热门文章失败");
        }
    }

    @Override
    public void changeCarouselIsused(ChangeCarouselIsusedDTO dto) {
        try {
            patientInfoDAO.updateCarouselIsused(dto.getId(), dto.getIsused());
        } catch (Exception e) {
            log.error("修改轮播图状态失败", e);
            throw new BusinessException("修改轮播图状态失败");
        }
    }

    @Override
    public void changeHotArticleIsused(ChangeHotArticleIsusedDTO dto) {
        try {
            patientInfoDAO.updateHotArticleIsused(dto.getId(), dto.getIsused());
        } catch (Exception e) {
            log.error("修改热门文章状态失败", e);
            throw new BusinessException("修改热门文章状态失败");
        }
    }

    @Override
    public void updateCarousel(UpdateCarouselDTO dto) {
        try {
            patientInfoDAO.updateCarousel(dto.getId(), dto.getPicture());
        } catch (Exception e) {
            log.error("修改轮播图信息失败", e);
            throw new BusinessException("修改轮播图信息失败");
        }
    }

    @Override
    public void updateHotArticle(UpdateHotArticleDTO dto) {
        try {
            patientInfoDAO.updateHotArticle(dto);
        } catch (Exception e) {
            log.error("修改热门文章信息失败", e);
            throw new BusinessException("修改热门文章信息失败");
        }
    }

    /**
     * 查询所有药品信息
     */
    @Override
    public List<Drug> getAllDrug() {
        try {
            return patientInfoDAO.getAllDrug();
        } catch (Exception e) {
            log.error("获取药品列表失败", e);
            throw new BusinessException("获取药品列表失败");
        }
    }

    /**
     * 修改药品启用状态
     */
    @Override
    public boolean changeDrugUse(Long id, String isused) {
        try {
            int rows = patientInfoDAO.updateDrugUse(id, isused);
            return rows > 0;
        } catch (Exception e) {
            log.error("修改药品状态失败, id:{}", id, e);
            throw new BusinessException("修改药品状态失败");
        }
    }

    /**
     * 添加药品
     */
    @Override
    public boolean addDrug(AddDrugDTO addDrugDTO) {
        try {
            Drug drug = new Drug();
            drug.setName(addDrugDTO.getName());
            drug.setMethod(addDrugDTO.getMethod());
            drug.setRemark(addDrugDTO.getRemark());
            int rows = patientInfoDAO.addDrug(drug);
            return rows > 0;
        } catch (Exception e) {
            log.error("添加药品失败", e);
            throw new BusinessException("添加药品失败");
        }
    }

    /**
     * 修改药品信息
     */
    @Override
    public boolean changeDrug(UpdateDrugDTO updateDrugDTO) {
        try {
            Drug drug = new Drug();
            drug.setId(updateDrugDTO.getId());
            drug.setName(updateDrugDTO.getName());
            drug.setMethod(updateDrugDTO.getMethod());
            drug.setRemark(updateDrugDTO.getRemark());
            int rows = patientInfoDAO.updateDrug(drug);
            return rows > 0;
        } catch (Exception e) {
            log.error("修改药品信息失败, id:{}", updateDrugDTO.getId(), e);
            throw new BusinessException("修改药品信息失败");
        }
    }

    @Override
    public List<ReviewInfoVO> getReviewInfo(String hospitalNumber, String reviewItem, String startTime, String endTime) throws Exception {
        return patientInfoDAO.getReviewInfo(hospitalNumber, reviewItem, startTime, endTime);
    }


    @Override
    public List<PatientInfoWithRegisterVO> selectPatientInfo(String gender, int startAge, int endAge, String disease, String isRegister) throws Exception {
        List<PatientInfoWithRegisterVO> result = new ArrayList<>();
        if ("已注册".equals(isRegister)) {
            List<PatientInfoVO> registeredVos = patientInfoDAO.selectPatientInfo(gender, startAge, endAge, disease);
            for (PatientInfoVO vo : registeredVos) {
                String idC = patientInfoDAO.getIdcByHospitalNumber(vo.getHospitalNumber());
                PatientInfoWithRegisterVO withRegisterVO = new PatientInfoWithRegisterVO(vo, "已注册");
                withRegisterVO.setIdCard(idC);
                result.add(withRegisterVO);
            }
        } else if ("未注册".equals(isRegister)) {
            List<UnregisteredPatientDTO> unregisteredPatients = patientInfoDAO.getUnregisteredPatients(disease);
            for (UnregisteredPatientDTO dto : unregisteredPatients) {
                PatientInfoWithRegisterVO vo = PatientInfoWithRegisterVO.builder()
                        .hospitalNumber(dto.getHospitalNumber())
                        .idCard(dto.getIdCard())
                        .disease(dto.getAuthority())  // 将 authority 作为 disease
                        .isRegister("未注册")
                        .build();
                result.add(vo);
            }
        } else if ("全部".equals(isRegister)) {
            List<PatientInfoWithRegisterVO> registeredPatients = selectPatientInfo(gender, startAge, endAge, disease, "已注册");
            List<PatientInfoWithRegisterVO> unregisteredPatients = selectPatientInfo(gender, startAge, endAge, disease, "未注册");
            result.addAll(registeredPatients);
            result.addAll(unregisteredPatients);
        }
        return result;
    }

    @Override
    public Result<String> checkInfoWrite(String hospitalNumber) {
        PatientInfo patientInfo = patientInfoDAO.getPatientAllInfoByHospitalNumber(hospitalNumber);
        if (patientInfo == null) {
            return Result.error("请完善信息");
        }
        LocalDateTime updateTime = patientInfo.getUpdateTime();
        LocalDateTime now = LocalDateTime.now();
        Duration duration = Duration.between(updateTime, now);
        if (duration.toDays() > 30 || patientInfo.getReVisitsNum() == 0) {
            return Result.error("请更新信息");
        }
        return Result.success("成功");
    }

    @Override
    public void insertNurseInfo(NurseInfoDTO nurseInfoDTO) throws Exception {

        String hospitalNumber = nurseInfoDTO.getHospitalNumber();
        // 1.对住院号进行查找
        Integer reVisitsNum = patientInfoDAO.getPatientReVisitsNum(hospitalNumber);
        String encryptPhone = nurseInfoDTO.getPhone();
//        if (encryptPhone != null && !encryptPhone.isEmpty()) {
//            encryptPhone = desUtil.encrypt(encryptPhone, DesUtil.CBC);
//        }
        // 编程式事务
        String finalEncryptPhone = encryptPhone;
        transactionTemplate.execute(status -> {
            try {
                // 2. 没有就新增病人信息
                if (reVisitsNum == null) {
                    PatientInfo patientInfo = PatientInfo.builder()
                            .hospitalNumber(hospitalNumber)
                            .gender(nurseInfoDTO.getGender())
                            .age(nurseInfoDTO.getAge())
//                            .stomaType(nurseInfoDTO.getStomaType())
                            .surgeryDate(nurseInfoDTO.getSurgeryDate())
                            .address(nurseInfoDTO.getAddress())
                            .phone(finalEncryptPhone)
                            .disease("泌尿造口")
                            .reVisitsNum(1)
                            .createTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .build();
                    patientInfoDAO.insert(patientInfo);
                } else {
                    // 3.有就更新病人信息
                    PatientInfo patientInfo = PatientInfo.builder()
                            .hospitalNumber(hospitalNumber)
                            .gender(nurseInfoDTO.getGender())
                            .age(nurseInfoDTO.getAge())
//                            .stomaType(nurseInfoDTO.getStomaType())
                            .surgeryDate(nurseInfoDTO.getSurgeryDate())
                            .address(nurseInfoDTO.getAddress())
                            .phone(finalEncryptPhone)
                            .reVisitsNum(reVisitsNum + 1)
                            .updateTime(LocalDateTime.now())
                            .build();
                    patientInfoDAO.update(patientInfo);
                }
                // 4. 新增回访信息表
                ReturnVisitList returnVisitList = ReturnVisitList.builder()
                        .hospitalNumber(nurseInfoDTO.getHospitalNumber())
                        .stomaType(nurseInfoDTO.getStomaType())
                        .reVisitsNum(reVisitsNum == null ? 1 : reVisitsNum + 1)
                        .stomaCatheter(nurseInfoDTO.getStomaCatheter())
                        .catheterDisplacement(nurseInfoDTO.getCatheterDisplacement())
                        .catheterBlockage(nurseInfoDTO.getCatheterBlockage())
                        .catheterReplacement(nurseInfoDTO.getCatheterReplacement())
                        .catheterNotes(nurseInfoDTO.getCatheterNotes())
                        .peristomalDermatitis(nurseInfoDTO.getPeristomalDermatitis())
                        .skinDamage(nurseInfoDTO.getSkinDamage())
                        .dermatitisRange(nurseInfoDTO.getDermatitisRange())
                        .dermatitisLocation(nurseInfoDTO.getDermatitisLocation())
                        .urinaryTractInfection(nurseInfoDTO.getUrinaryTractInfection())
                        .fever(nurseInfoDTO.getFever())
                        .backPain(nurseInfoDTO.getBackPain())
                        .backPainNote(nurseInfoDTO.getBackPainNote())
                        .cloudyUrine(nurseInfoDTO.getCloudyUrine())
                        .cloudyUrineNote(nurseInfoDTO.getCloudyUrineNote())
                        .exercise(nurseInfoDTO.getExercise())
                        .bath(nurseInfoDTO.getBath())
                        .diet(nurseInfoDTO.getDiet())
                        .drink(nurseInfoDTO.getDrink())
                        .dietDrinkNote(nurseInfoDTO.getDietDrinkNote())
                        .replaceMethod(nurseInfoDTO.getReplaceMethod())
                        .chassisCycle(nurseInfoDTO.getChassisCycle())
                        .bagCycle(nurseInfoDTO.getBagCycle())
                        .acquisitionMethod(nurseInfoDTO.getAcquisitionMethod())
                        .note(nurseInfoDTO.getNote())
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now()).build();

                returnVisitListDAO.insert(returnVisitList);

                // 数据异常告警
                List<String> exceptionList = nurseInfoDTO.isExceptionList();
                if (exceptionList != null && !exceptionList.isEmpty()) {
                    patientExceptionService.insert(exceptionList, nurseInfoDTO.getHospitalNumber());
                }

            } catch (Exception e) {
                status.setRollbackOnly();
                throw new RuntimeException(e);
            }
            return null;
        });
    }

    @Override
    public PatientInfoVO getPatientInfoByHospitalNumber(String hospitalNumber) {

        PatientInfo patientInfo = patientInfoDAO.getPatientInfoByHospitalNumber(hospitalNumber);

        if (patientInfo == null) {
            return null;
        }

        return PatientInfoVO.builder()
                .hospitalNumber(patientInfo.getHospitalNumber())
                .gender(patientInfo.getGender())
                .age(patientInfo.getAge())
//                .stomaType(patientInfo.getStomaType())
                .surgeryDate(patientInfo.getSurgeryDate())
                .address(patientInfo.getAddress())
                .phone(patientInfo.getPhone())
                .reVisitsNum(patientInfo.getReVisitsNum())
                .build();
    }

    @Override
    public int getPatientReVisitsCountToday() {
        int res = returnVisitListDAO.getPatientReVisitsCountToday();
        return res;
    }

    @Override
    public List<PatientInfoReturnVisitListVO> getPatientInfoReturnVisitList() {
        return getPatientInfoReturnVisitList(null, null);
    }

    @Override
    public List<PatientInfoReturnVisitListVO> getPatientInfoReturnVisitList(Date startTime, Date endTime) {
        List<PatientInfo> patientInfos = patientInfoDAO.getPatientInfo();
        List<PatientInfoReturnVisitListVO> patientInfoReturnVisitListVOs = new ArrayList<>();
        for (PatientInfo patientInfo : patientInfos) {
            // 根据住院号获取该病人的回访记录
            List<ReturnVisitList> returnVisitLists = returnVisitListDAO.getReturnVisitListByHospitalNumber(patientInfo.getHospitalNumber(), startTime, endTime);
            for (ReturnVisitList returnVisitList : returnVisitLists) {
                PatientInfoReturnVisitListVO patientInfoReturnVisitListVO = PatientInfoReturnVisitListVO.builder()
                        .id(returnVisitList.getId())
                        .stomaType(returnVisitList.getStomaType())
                        .reVisitsNum(returnVisitList.getReVisitsNum())
                        .stomaCatheter(returnVisitList.getStomaCatheter().equals("无") ? "无" : "有")
                        .catheterDisplacement(returnVisitList.getCatheterDisplacement().equals("无") ? "无" : "有")
                        .catheterBlockage(returnVisitList.getCatheterBlockage())
                        .catheterReplacement(returnVisitList.getCatheterReplacement())
                        .catheterNotes(returnVisitList.getCatheterNotes())
                        .peristomalDermatitis(returnVisitList.getPeristomalDermatitis().equals("无") ? "无" : "有")
                        .skinDamage(returnVisitList.getSkinDamage())
                        .dermatitisRange(returnVisitList.getDermatitisRange())
                        .dermatitisLocation(returnVisitList.getDermatitisLocation())
                        .urinaryTractInfection(returnVisitList.getUrinaryTractInfection())
                        .fever(returnVisitList.getFever())
                        .backPain(returnVisitList.getBackPain())
                        .backPainNote(returnVisitList.getBackPainNote())
                        .cloudyUrine(returnVisitList.getCloudyUrine())
                        .cloudyUrineNote(returnVisitList.getCloudyUrineNote())
                        .exercise(returnVisitList.getExercise())
                        .bath(returnVisitList.getBath())
                        .diet(returnVisitList.getDiet())
                        .drink(returnVisitList.getDrink())
                        .dietDrinkNote(returnVisitList.getDietDrinkNote())
                        .replaceMethod(returnVisitList.getReplaceMethod())
                        .chassisCycle(returnVisitList.getChassisCycle())
                        .bagCycle(returnVisitList.getBagCycle())
                        .acquisitionMethod(returnVisitList.getAcquisitionMethod())
                        .note(returnVisitList.getNote())
                        .build();
                String[] split = patientInfo.getSurgeryDate().split(" ");
                patientInfoReturnVisitListVO.setHospitalNumber(patientInfo.getHospitalNumber());
                patientInfoReturnVisitListVO.setGender(patientInfo.getGender());
                patientInfoReturnVisitListVO.setAge(patientInfo.getAge());
                patientInfoReturnVisitListVO.setSurgeryDate(split[split.length - 1]);
                patientInfoReturnVisitListVO.setAddress(patientInfo.getAddress());
                patientInfoReturnVisitListVO.setPhone(patientInfo.getPhone());
                patientInfoReturnVisitListVO.setReVisitsNum(patientInfo.getReVisitsNum());
                patientInfoReturnVisitListVOs.add(patientInfoReturnVisitListVO);
            }

        }
        return patientInfoReturnVisitListVOs;
    }

    @Override
    public void deleteReturnVisitList(List<Long> ids) {
        returnVisitListDAO.deleteByIds(ids);
    }

    @Override
    public void deletePatientInfoProstateCancerList(List<Long> ids) {
        prostateCancerDAO.deleteByIds(ids);
    }

    @Override
    public void insertProstateSurgeryInfo(ProstateSurgeryInfoDTO prostateSurgeryInfoDTO) {

        String hospitalNumber = prostateSurgeryInfoDTO.getHospitalNumber();
        // 1.对住院号进行查找
        Integer reVisitsNum = patientInfoDAO.getPatientReVisitsNum(hospitalNumber);
        // 编程式事务
        transactionTemplate.execute(status -> {
            try {
                // 2. 没有就新增病人信息
                if (reVisitsNum == null) {
                    log.info("prostateSurgeryInfoDTO is " + prostateSurgeryInfoDTO.toString());
                    PatientInfo patientInfo = PatientInfo.builder()
                            .hospitalNumber(prostateSurgeryInfoDTO.getHospitalNumber())
                            .gender(prostateSurgeryInfoDTO.getGender())
                            .age(prostateSurgeryInfoDTO.getAge())
                            .surgeryDate(prostateSurgeryInfoDTO.getTotalSurgeryDate())
                            .disease("前列腺疾病")
                            .address(prostateSurgeryInfoDTO.getAddress())
                            .phone(prostateSurgeryInfoDTO.getPhone())
                            .name(prostateSurgeryInfoDTO.getName())
                            .reVisitsNum(1)
                            .createTime(LocalDateTime.now())
                            .updateTime(LocalDateTime.now())
                            .build();
                    patientInfoDAO.insert(patientInfo);
                } else {
                    // 3.有就更新病人信息
                    PatientInfo patientInfo = PatientInfo.builder()
                            .hospitalNumber(prostateSurgeryInfoDTO.getHospitalNumber())
                            .gender(prostateSurgeryInfoDTO.getGender())
                            .age(prostateSurgeryInfoDTO.getAge())
                            .surgeryDate(prostateSurgeryInfoDTO.getTotalSurgeryDate())
                            .address(prostateSurgeryInfoDTO.getAddress())
                            .phone(prostateSurgeryInfoDTO.getPhone())
                            .name(prostateSurgeryInfoDTO.getName())
                            .reVisitsNum(reVisitsNum + 1)
                            .updateTime(LocalDateTime.now())
                            .build();
                    patientInfoDAO.update(patientInfo);
                }
                //todo 4. 新增回访信息表
                ProstateCancer prostateCancer = ProstateCancer.builder()
                        .hospitalNumber(prostateSurgeryInfoDTO.getHospitalNumber())
                        .reVisitsNum(reVisitsNum == null ? 1 : reVisitsNum + 1)
                        .diagnosisMethod(prostateSurgeryInfoDTO.getDiagnosisMethod())
                        .pathologyResult(prostateSurgeryInfoDTO.getPathologyResult())
                        .diagnosisTime(prostateSurgeryInfoDTO.getDiagnosisTime())
                        .psaAtDiagnosis(prostateSurgeryInfoDTO.getPsaAtDiagnosis())
                        .preoperativeMedication(prostateSurgeryInfoDTO.getPreoperativeMedication())
                        .beforeMedicationName(prostateSurgeryInfoDTO.getBeforeMedicationName())
                        .beforeMedicationStartTime(prostateSurgeryInfoDTO.getBeforeMedicationStartTime())
                        .psaAfterMedication(prostateSurgeryInfoDTO.getPsaAfterMedication())
                        .surgeryType(prostateSurgeryInfoDTO.getSurgeryType())
                        .surgeryTime(prostateSurgeryInfoDTO.getSurgeryTime())
                        .postoperativePathologyResult(prostateSurgeryInfoDTO.getPostoperativePathologyResult())
                        .urinaryIncontinenceAfterSurgery(prostateSurgeryInfoDTO.getUrinaryIncontinenceAfterSurgery())
                        .urinaryPadNumber(prostateSurgeryInfoDTO.getUrinaryPadNumber())
                        .otherPostoperativeDiscomfort(prostateSurgeryInfoDTO.getOtherPostoperativeDiscomfort())
                        .postoperativeMedication(prostateSurgeryInfoDTO.getPostoperativeMedication())
                        .afterMedicationName(prostateSurgeryInfoDTO.getAfterMedicationName())
                        .afterMedicationStarttime(prostateSurgeryInfoDTO.getAfterMedicationStarttime())
                        .psaRecheckTime(prostateSurgeryInfoDTO.getPsaRecheckTime())
                        .psaRecheckValue(prostateSurgeryInfoDTO.getPsaRecheckValue())
                        .createTime(LocalDateTime.now())
                        .updateTime(LocalDateTime.now())
                        .build();
                prostateCancerDAO.insert(prostateCancer);
                // 数据异常告警w
//                // 数据异常告警
//                List<String> exceptionList = prostateSurgeryInfoDTO.isExceptionList();
//                if (exceptionList != null && !exceptionList.isEmpty()) {
//                    patientExceptionService.insert(exceptionList, nurseInfoDTO.getHospitalNumber());
//                }

            } catch (Exception e) {
                status.setRollbackOnly();
                throw new RuntimeException(e);
            }
            return null;
        });
    }

    @Override
    public List<PatientInfoProstateCancerVO> getPatientInfoProstateCancerList() {
        return getPatientInfoProstateCancerList(null, null);
    }

    @Override
    public List<PatientInfoProstateCancerVO> getPatientInfoProstateCancerList(Date startTime, Date endTime) {
        //List<PatientInfo> patientInfos = patientInfoDAO.getProstateCancerPatientInfo("前列腺癌");
        List<PatientInfo> patientInfos = patientInfoDAO.getPatientInfo();
        List<PatientInfoProstateCancerVO> patientInfoProstateCancerVOS = new ArrayList<>();
        for (PatientInfo patientInfo : patientInfos) {
            List<ProstateCancer> prostateCancerList = prostateCancerDAO.getProstateCancerListByHospitalNumber(patientInfo.getHospitalNumber(), startTime, endTime);
            for (ProstateCancer prostateCancer : prostateCancerList) {
                PatientInfoProstateCancerVO patientInfoProstateCancerVO = PatientInfoProstateCancerVO.builder()
                        .id(prostateCancer.getId())
                        .hospitalNumber(prostateCancer.getHospitalNumber())
                        .diagnosisMethod(prostateCancer.getDiagnosisMethod())
                        .pathologyResult(prostateCancer.getPathologyResult())
                        .diagnosisTime(prostateCancer.getDiagnosisTime())
                        .psaAtDiagnosis(prostateCancer.getPsaAtDiagnosis())
                        .preoperativeMedication(prostateCancer.getPreoperativeMedication())
                        .beforeMedicationName(prostateCancer.getBeforeMedicationName())
                        .beforeMedicationStartTime(prostateCancer.getBeforeMedicationStartTime())
                        .psaAfterMedication(prostateCancer.getPsaAfterMedication())
                        .surgeryType(prostateCancer.getSurgeryType())
                        .surgeryTime(prostateCancer.getSurgeryTime())
                        .postoperativePathologyResult(prostateCancer.getPostoperativePathologyResult())
                        .urinaryIncontinenceAfterSurgery(prostateCancer.getUrinaryIncontinenceAfterSurgery())
                        .urinaryPadNumber(prostateCancer.getUrinaryPadNumber())
                        .recoveryTimeWithoutPad(prostateCancer.getRecoveryTimeWithoutPad())
                        .otherPostoperativeDiscomfort(prostateCancer.getOtherPostoperativeDiscomfort())
                        .postoperativeMedication(prostateCancer.getPostoperativeMedication())
                        .afterMedicationName(prostateCancer.getAfterMedicationName())
                        .afterMedicationStarttime(prostateCancer.getAfterMedicationStarttime())
                        .psaRecheckTime(prostateCancer.getPsaRecheckTime())
                        .psaRecheckValue(prostateCancer.getPsaRecheckValue())
                        .build();
                String[] split = patientInfo.getSurgeryDate().split(" ");
                patientInfoProstateCancerVO.setHospitalNumber(patientInfo.getHospitalNumber());
                patientInfoProstateCancerVO.setGender(patientInfo.getGender());
                patientInfoProstateCancerVO.setAge(patientInfo.getAge());
                patientInfoProstateCancerVO.setSurgeryDate(split[split.length - 1]);
                patientInfoProstateCancerVO.setAddress(patientInfo.getAddress());
                patientInfoProstateCancerVO.setPhone(patientInfo.getPhone());
                patientInfoProstateCancerVO.setName(patientInfo.getName());
                patientInfoProstateCancerVO.setReVisitsNum(patientInfo.getReVisitsNum());
                patientInfoProstateCancerVO.setDisease(patientInfo.getDisease());
                patientInfoProstateCancerVOS.add(patientInfoProstateCancerVO);
            }
        }
        return patientInfoProstateCancerVOS;
    }

    @Override
    public void addPatient(String hospitalNumber, String authority, String idCard, String limRevisitTime) throws Exception {
        // 检查身份证号是否已注册
        if (patientInfoDAO.getIdByIdCard(idCard) != null) {
            throw new BusinessException("身份证号已注册");
        }

        // 如果hospitalNumber为0，则生成随机6位数字
        if ("0".equals(hospitalNumber)) {
            Random random = new Random();
            boolean isUnique = false;

            // 循环生成直到获得唯一的6位数字
            while (!isUnique) {
                // 生成100000-999999之间的随机数
                int randomNum = random.nextInt(900000) + 100000;
                hospitalNumber = String.valueOf(randomNum);

                // 检查是否已存在
                if (patientInfoDAO.getIdByHospitalNumber(hospitalNumber) == null) {
                    isUnique = true;
                }
            }
        } else {
            // 检查住院号是否存在
            if (patientInfoDAO.getIdByHospitalNumber(hospitalNumber) != null) {
                throw new BusinessException("住院号已存在");
            }
        }

        // 创建新患者记录
        PatientInit patientInit = PatientInit.builder()
                .hospitalNumber(hospitalNumber)
                .authority(authority)
                .idCard(idCard)  // 新增字段
                .limRevisitTime(limRevisitTime)  // 新增字段
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();

        try {
            patientInfoDAO.insertPatientInit(patientInit);
        } catch (DuplicateKeyException e) {
            throw new BusinessException("住院号已存在");
        } catch (Exception e) {
            log.error("数据库插入异常: {}", e.getMessage());
            throw new Exception("系统错误，请稍后重试");
        }
    }

    @Override
    public void deletePatient(String hospitalNumber) throws Exception {
        // 检查住院号是否存在
        Long patientId = patientInfoDAO.getIdByHospitalNumber(hospitalNumber);
        if (patientId == null) {
            throw new BusinessException("住院号不存在");
        }

        try {
            patientInfoDAO.deleteByHospitalNumber(hospitalNumber);
            patientInfoDAO.deletePatientInfoByHospitalNumber(hospitalNumber);
            patientInfoDAO.deleteLoginByHospitalNumber(hospitalNumber);
            patientInfoDAO.deleteMNZKHospitalNumber(hospitalNumber);
            patientInfoDAO.deleteQLXAHospitalNumber(hospitalNumber);
        } catch (Exception e) {
            log.error("数据库删除异常: {}", e.getMessage());
            throw new Exception("系统错误，请稍后重试");
        }
    }

    @Override
    public Result<String> register(PatientLoginDTO patientLoginDTO) {
        // 检查用户名是否已存在
        PatientLoginDTO existingUser = patientInfoDAO.getPatientByUsername(patientLoginDTO.getPatientUserName());
        if (existingUser != null) {
            return Result.error("用户名已存在");
        }
        PatientLoginDTO existingUserByIDNumber = patientInfoDAO.getPatientByIdNumber(patientLoginDTO.getIdNumber());
        if (existingUserByIDNumber != null) {
            return Result.error("身份证号已被注册");
        }

        try {
            // 获取医院编号并处理可能的异常
            String hospitalNumber = patientInfoDAO.getHospitalNumberByIdCard(patientLoginDTO.getIdNumber());
            // 新增：校验医院编号是否为null
            if (hospitalNumber == null || hospitalNumber.trim().isEmpty()) {
                return Result.error("身份证号未注册，请联系医护人员处理");
            }
            patientLoginDTO.setHospitalNumber(hospitalNumber);
        } catch (Exception e) {
            // 记录异常日志
            log.error("获取医院编号时发生异常", e);
            return Result.error("系统错误");
        }

        // 加密密码
        String encryptedPassword = Md5Util.getMD5String(patientLoginDTO.getPassword());
        patientLoginDTO.setPassword(encryptedPassword);
        patientLoginDTO.setCreateTime(LocalDateTime.now());
        patientLoginDTO.setUpdateTime(LocalDateTime.now());

        try {
            // 插入注册信息并处理可能的异常
            patientInfoDAO.insertPatientLogin(patientLoginDTO);
        } catch (Exception e) {
            // 记录异常日志
            log.error("插入患者注册信息时发生异常", e);
            return Result.error("系统错误");
        }

        return Result.success("注册成功");
    }

    @Override
    public Result<String> sendVerificationCode(String phoneNumber) {
        try {
            // 生成验证码
            String verificationCode = String.format("%06d", new Random().nextInt(1000000));
            boolean success = smsService.sendVerificationCode(phoneNumber, verificationCode);
            if (!success) {
                return Result.error("验证码发送失败");
            }
            // 存储验证码到 Redis，有效期 180 秒
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(phoneNumber, verificationCode, 180, TimeUnit.SECONDS);
            // 这里可以添加实际的短信发送逻辑
            return Result.success("succeed");
        } catch (Exception e) {
            log.error("发送验证码异常: {}", e.getMessage());
            return Result.error("验证码发送失败");
        }
    }

    @Override
    public Result<String> resetKey(PatientLoginDTO patientLoginDTO) {
        PatientLoginDTO ifExistPatient = patientInfoDAO.getPatientByHospitalNumberAndIdNumber(patientLoginDTO);
        if (ifExistPatient == null) {
            return Result.error("验证失败,请仔细检查是否填错");
        }
        // 加密新密码
        String encryptedPassword = Md5Util.getMD5String(patientLoginDTO.getPassword());
        System.out.println(encryptedPassword);
        patientLoginDTO.setPassword(encryptedPassword);
        patientLoginDTO.setUpdateTime(LocalDateTime.now());
        // 更新数据库
        patientInfoDAO.updatePatientPassword(patientLoginDTO);
        System.out.println("重置密码成功");
        return Result.success("重置密码成功");
    }

    @Override
    public Result<Map<String, Object>> login(PatientLoginDTO patientLoginDTO) throws Exception {
        // 根据用户名查找用户
        String input = patientLoginDTO.getPatientUserName();
        PatientLoginDTO loginUser;
        if (CheckIdNumberUtil.validateIdCard(input)) {
            // 如果输入全部由数字组成，使用住院号密码登录
            loginUser = patientInfoDAO.getPatientByIdNumber(input);
        } else {
            // 否则使用用户名密码登录
            loginUser = patientInfoDAO.getPatientByUsername(input);
        }
        if (loginUser == null) {
            return Result.error("用户名或身份证号错误");
        }

        // 比对密码
        String encryptedPassword = Md5Util.getMD5String(patientLoginDTO.getPassword());
        if (encryptedPassword.equals(loginUser.getPassword())) {
            Map<String, Object> claims = new HashMap<>();
            claims.put("hospitalNumber", loginUser.getHospitalNumber());
            claims.put("patientUsername", loginUser.getPatientUserName());
            String token = JwtUtil.genToken(claims);

            // 把 token 存储到 redis 中
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            operations.set(token, token, 1, TimeUnit.HOURS);
            String authority = patientInfoDAO.getAuthorityByHospitalNumber(loginUser.getHospitalNumber());
            String idCard = patientInfoDAO.getIdCardByHospitalNumber(loginUser.getHospitalNumber());
            PatientInfo patientInfo = patientInfoDAO.getPatientInfoByHospitalNumber(loginUser.getHospitalNumber());
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("token", token);
            resultMap.put("username", loginUser.getPatientUserName());
            resultMap.put("hospitalNumber", loginUser.getHospitalNumber());
            resultMap.put("authority", authority);
            resultMap.put("idCard", idCard);
//            没有填报过patientInfo
            if (patientInfo == null) {
                resultMap.put("gender", "");
                resultMap.put("age", "");
                resultMap.put("surgery_date", "");
                resultMap.put("disease", "");
                resultMap.put("address", new String[0]);
                resultMap.put("detailAddress", "");
                resultMap.put("phone", "");
                resultMap.put("hasRegisteredInfo", 0);
            } else {
                resultMap.put("gender", patientInfo.getGender());
                resultMap.put("age", patientInfo.getAge());
                resultMap.put("surgery_date", patientInfo.getSurgeryDate().split(" "));
                resultMap.put("disease", patientInfo.getDisease());
                String address = patientInfo.getAddress();
                if (address.isEmpty()) {
                    resultMap.put("address", new String[0]);
                    resultMap.put("detailAddress", "");
                } else {
                    String[] split = patientInfo.getAddress().split(" ");
                    if (split.length <= 3) {
                        resultMap.put("address", split);
                        resultMap.put("detailAddress", "");
                    } else {
                        resultMap.put("address", Arrays.copyOf(split, 3));
                        resultMap.put("detailAddress", split[3]);
                    }
                }
                resultMap.put("phone", patientInfo.getPhone());
                resultMap.put("hasRegisteredInfo", 1);
            }

            return Result.success(resultMap);
        }
        return Result.error("密码错误");
    }

    @Override
    public Result<Map<String, Object>> changePatientInfo(PatientInfo patientInfo) {
        String hospitalNumber = patientInfo.getHospitalNumber();
//        用hospitalNumber找是否有对应的patientInfo
        PatientInfo patient = patientInfoDAO.getPatientInfoByHospitalNumber(hospitalNumber);
        if (patient == null) {
//            用户还没有填过表单,插入
            PatientInfo patientInfoToUpdate = PatientInfo.builder()
                    .hospitalNumber(hospitalNumber)
                    .gender(patientInfo.getGender())
                    .age(patientInfo.getAge())
                    .surgeryDate("")
                    .disease("")
                    .address("")
                    .phone("")
                    .reVisitsNum(0)
                    .createTime(LocalDateTime.now())
                    .updateTime(LocalDateTime.now())
                    .build();
            patientInfoDAO.insert(patientInfoToUpdate);
        } else {
//            用户插入过,修改
            PatientInfo patientInfoToUpdate = PatientInfo.builder()
                    .hospitalNumber(hospitalNumber)
                    .gender(patientInfo.getGender())
                    .age(patientInfo.getAge())
                    .surgeryDate(patient.getSurgeryDate())
                    .disease(patient.getDisease())
                    .address(patient.getAddress())
                    .phone(patient.getPhone())
                    .reVisitsNum(patient.getReVisitsNum())
                    //.updateTime(LocalDateTime.now())
                    .build();
            patientInfoDAO.update(patientInfoToUpdate);
        }
        return Result.success();
    }

    @Override
    public Result<List<ReturnVisitVO>> getReturnVisitList(String hospitalNumber, String gender, String idCard,
                                                          String startTime, String endTime) {
        List<ReturnVisitVO> returnVisitVOS = returnVisitListDAO.getReturnVisitVOs(hospitalNumber, gender, idCard, startTime, endTime);
        List<ReturnVisitVO> resultList = new ArrayList<>();
        for (ReturnVisitVO returnVisitVO : returnVisitVOS) {
            String[] surgeryDate = returnVisitVO.getSurgeryDate().split(" ");
            StringBuilder sb = new StringBuilder();
            sb.append("第1次手术:" + surgeryDate[0]);
            for (int i = 1; i < surgeryDate.length; i++) {
                sb.append(" ");
                sb.append("第" + (i + 1) + "次手术:" + surgeryDate[i]);
            }
            returnVisitVO.setSurgeryDate(sb.toString());
            resultList.add(returnVisitVO);
        }
        return Result.success(resultList);
    }

    @Override
    public Result<List<ProstateCancerVO>> getProstateCancerVOS(String hospitalNumber, String gender, String idCard, String startTime, String endTime) {
        List<ProstateCancerVO> prostateCancerVOS = prostateCancerDAO.getProstateCancerVOS(hospitalNumber, gender, idCard, startTime, endTime);
        List<ProstateCancerVO> resultList = new ArrayList<>();
        for (ProstateCancerVO prostateCancerVO : prostateCancerVOS) {
            String[] surgeryDate = prostateCancerVO.getSurgeryDate().split(" ");
            StringBuilder sb = new StringBuilder();
            sb.append("第1次手术:" + surgeryDate[0]);
            for (int i = 1; i < surgeryDate.length; i++) {
                sb.append(" ");
                sb.append("第" + (i + 1) + "次手术:" + surgeryDate[i]);
            }
            prostateCancerVO.setSurgeryDate(sb.toString());
            resultList.add(prostateCancerVO);
        }
        return Result.success(prostateCancerVOS);
    }

    @Override
    public Result<List<CycleRemindVO>> getCycleRemindInfo(String authority, String hospitalNumber, String idCard, String cycleInterval, String limitInterval, String ifBeyondInterval) {
//        这里只列出了填过表,在info中有信息的人
        List<CycleRemindVO> cycleRemindVOS = patientInfoDAO.getCycleRemindInfo(authority, hospitalNumber,
                idCard, cycleInterval, limitInterval, ifBeyondInterval);
//        找出在info中没有信息的病人
        if (cycleInterval.equals("全部") && ifBeyondInterval.equals("全部")) {
            List<CycleRemindVO> infoForRemind = patientInfoDAO.getPatientWithoutInfoForRemind(authority, hospitalNumber, idCard, limitInterval);
            for (CycleRemindVO cycle : infoForRemind) {
                cycle.setCycleInterval("未知");
                cycle.setIfBeyondInterval("未知");
                cycleRemindVOS.add(cycle);
            }
        }
        return Result.success(cycleRemindVOS);
    }

    @Override
    public Result changePatientInterval(String hospitalNumber, String newInterval) {
        try {
            patientInfoDAO.changePatientInterval(hospitalNumber, newInterval);
            return Result.success();
        } catch (Exception e) {
            return Result.error(e.getMessage());
        }
    }

}
